package com.duowan.cms.service.tag;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.duowan.cms.common.exception.BaseCheckedException;
import com.duowan.cms.common.service.DoToDtoConvertorFactory;
import com.duowan.cms.common.util.ChineseCharactersUtil;
import com.duowan.cms.common.util.DateUtil;
import com.duowan.cms.common.util.FileUtil;
import com.duowan.cms.common.util.PathUtil;
import com.duowan.cms.common.util.StringUtil;
import com.duowan.cms.common.util.ThreadUtil;
import com.duowan.cms.core.rmi.client.tag.TagRemoteService;
import com.duowan.cms.domain.article.rpst.Article4TagListRepository;
import com.duowan.cms.domain.article.rpst.ArticleRepository;
import com.duowan.cms.domain.channel.Channel;
import com.duowan.cms.domain.tag.Tag;
import com.duowan.cms.domain.tag.rpst.TagRepository;
import com.duowan.cms.dto.channel.ChannelInfo;
import com.duowan.cms.dto.tag.TagCategory;
import com.duowan.cms.dto.tag.TagInfo;
import com.duowan.cms.dto.tag.TagSearchCriteria;
import com.duowan.cms.dto.template.TemplateCategory;
import com.duowan.cms.dto.template.TemplateInfo;
import com.duowan.cms.dto.template.TemplateSearchCriteria;
import com.duowan.cms.parser.rmi.client.template.TemplateParserRemoteService;
import com.duowan.cms.service.channel.ChannelService;
import com.duowan.cms.service.template.TemplateService;

@Service("tagService")
public class TagServiceImpl implements TagService, TagRemoteService {

    @Autowired
    private ArticleRepository articleRepository;
    @Autowired
    private Article4TagListRepository article4TagListRepository;
    @Autowired
    private TagRepository tagRepository;
    @Autowired
    private TemplateParserRemoteService parserRemoteService;
    @Autowired
    private TemplateService templateService;
    @Autowired
    private ChannelService channelService;

    @Override
    public List<TagInfo> getRecentUpdateTag(String channelId, int minute) {
        TagSearchCriteria searchCriteria = new TagSearchCriteria();
        searchCriteria.setPageSize(null);
        searchCriteria.setChannelId(channelId);
        searchCriteria.setUpdateTime(DateUtil.getBeforeTime(minute));
        return tagRepository.pageSearch(searchCriteria).getData();
    }

    @SuppressWarnings("unchecked")
    @Override
    public TagInfo getByChannelIdAndName(String channelId, String name) {
        Tag tag = tagRepository.getByChannelIdAndName(channelId, name);
        return (TagInfo) DoToDtoConvertorFactory.getConvertor(Tag.class).do2Dto(tag);
    }

    @Override
    public List<TagInfo> getChildren(String channelId, String parent) {
        return tagRepository.getChildren(channelId, parent);
    }

    @Override
    public String getTagsExcludeSpecialToJson(String channelId) {
        return channelTag2Json(channelId, "").toJSONString();
    }

    @Override
    public String getTagTreeByPostTags(String channelId, String tagsStr) {
        return getTagTreeByPostTags(channelId, tagsStr, false);
    }

    @Override
    public int getMaxDepthOfSonTag(String channelId, String tagName) {
        List<TagInfo> sonTagInfoList = tagRepository.getDescendantIncludeSelf(channelId, tagName);
        int maxDepth = 0;
        for (TagInfo tagInfo : sonTagInfoList) {
            if (tagInfo.getTagDepth() > maxDepth) {
                maxDepth = tagInfo.getTagDepth();
            }

        }
        return maxDepth;
    }

    @Override
    public String getTagTreeByPostTagsExcludeSpecial(String channelId, String tagsStr) {
        return getTagTreeByPostTags(channelId, tagsStr, true);
    }

    private String getTagTreeByPostTags(String channelId, String tagsStr, boolean isExcludeSpecial) {
        String result = "";
        if (StringUtil.isEmpty(tagsStr))
            return "";
        String splitrRegex = ",|;"; // 使用，或者；来分隔
        String[] tags = tagsStr.split(splitrRegex);
        for (int i = 0; tags != null && i < tags.length; i++) {
            if (StringUtil.isEmpty(tags[i]))
                continue;
            Tag tag = tagRepository.getByChannelIdAndName(channelId, tags[i]);
            if (tag == null)
                continue;
            if (isExcludeSpecial)
                if (TagCategory.SPECIAL == tag.getCategory())
                    continue;
            result += tag.getTree();
        }
        return deleteDuplicateTags(result);

    }

    /**
     * 删除重复的tag （tags的格式为" ,tag1,tag2,tag3,tag4, "）
     * @param tagsStr
     * @return
     */
    private String deleteDuplicateTags(String tagsStr) {
        String result = ",";
        String[] tempTags = tagsStr.split(",|;");
        for (int i = 0; tempTags != null && i < tempTags.length; i++) {
            if (StringUtil.isEmpty(tempTags[i]))
                continue;
            if (result.indexOf("," + tempTags[i] + ",") == -1)
                result += tempTags[i] + ",";
        }
        if(result.length() > 1)//去掉第一个","
            return result.substring(1, result.length());
        return result;
    }

    @Override
    public String addTagStr(String tags, String tag) {
        if (StringUtil.isEmpty(tags))
            return "," + tag + ",";
        if (tags.indexOf("," + tag + ",") == -1)
            tags += tag + ",";
        return tags;
    }

    /**
     * 将tag的子孙树(不包含特殊tag)转化成json数据。
     * @author yzq
     * @param channelId
     * @param tag
     * @return
     */
    private JSONArray channelTag2Json(String channelId, String tag) {
        List<TagInfo> list = tagRepository.getTagsExcludeSpecial(channelId);
        // list按拼音排序
        Collections.sort(list, new Comparator<TagInfo>() {
            public int compare(TagInfo o1, TagInfo o2) {
                String name1 = ChineseCharactersUtil.String2Alpha(o1.getName());
                String name2 = ChineseCharactersUtil.String2Alpha(o2.getName());
                return name1.compareTo(name2);
            }
        });

        Map<String, List<TagInfo>> map = new HashMap<String, List<TagInfo>>();
        for (TagInfo tagInfo : list) {
            // 将list中tag信息按(标签名,标签的子标签信息列表)存放到map中
            map.put(tagInfo.getName(), getSon(tagInfo.getName(), list));
        }
        // 得到tag子标签信息列表
        List<TagInfo> sonList = getSon(tag, list);
        return sonList2Json(sonList, map);
    }

    /**
     * 筛选：从list中选取TagInfo的parentName为parent的列表。
     * @author yzq
     * @param parent
     * @param list
     * @return
     */
    private List<TagInfo> getSon(String parent, List<TagInfo> list) {

        List<TagInfo> sonList = new ArrayList<TagInfo>();

        for (TagInfo tag : list) {
            if (tag.getParentName().equals(parent)) {
                sonList.add(tag);
            }
        }
        return sonList;
    }

    /**
     * 将list中tag数据转化为json,从map中找寻其子孙数据
     * @author yzq
     * @param list
     * @param map
     * @return
     */
    @SuppressWarnings("unchecked")
    private JSONArray sonList2Json(List<TagInfo> list, Map<String, List<TagInfo>> map) {

        JSONArray jarray = new JSONArray();
        String son = "";

        //List<String> temp_list = new ArrayList<String>();

        for (TagInfo tagInfo : list) {

            son = tagInfo.getName();

            List<TagInfo> tags = map.get(son);

            if (tags.isEmpty() || StringUtil.isEmpty(son)) {
                jarray.add(son);//temp_list.add(son);
            } else {
                JSONObject jobj = new JSONObject();
                jobj.put(son, sonList2Json(tags, map));
                jarray.add(jobj);
            }
        }

        //jarray.addAll(temp_list);

        return jarray;
    }

    public List<TagInfo> getSpecialTags(String channelId) {
        return tagRepository.getSpecialTags(channelId);
    }

    public List<TagInfo> getAllTagsInChannel(String channelId) {
        List<TagInfo> list = tagRepository.getAllTagsInChannel(channelId);
        
        // list按拼音排序
        Collections.sort(list, new Comparator<TagInfo>() {
            public int compare(TagInfo o1, TagInfo o2) {
                String name1 = ChineseCharactersUtil.String2Alpha(o1.getName());
                String name2 = ChineseCharactersUtil.String2Alpha(o2.getName());
                return name1.compareTo(name2);
            }
        });
        
        Map<String, List<TagInfo>> map = new HashMap<String, List<TagInfo>>();
        for (TagInfo tagInfo : list) {
            // 将list中tag信息按(标签名,标签的子标签信息列表)存放到map中
            map.put(tagInfo.getName(), getSon(tagInfo.getName(), list));
        }
        
        //得到一级标签
        List<TagInfo> sonList = getSon("", list);
        
        return sortList(sonList, map);
    }
    
    private List<TagInfo> sortList(List<TagInfo> list, Map<String, List<TagInfo>> map){
        List<TagInfo> resultList = new ArrayList<TagInfo>();
        
        String son = null;
        
        for (TagInfo tagInfo : list) {

            resultList.add(tagInfo);
            
            son = tagInfo.getName();

            List<TagInfo> tags = map.get(son);
            
            if(null != tags && !tags.isEmpty()){
                resultList.addAll(sortList(tags, map));
            }
        }
        
        return resultList;
    }

    public void addChild(TagInfo tagInfo) {
        Tag tag = new Tag(tagInfo);
        tagRepository.save(tag);
        this.asynParseTagAndGenerateFile(tagInfo.getChannelId(), tagInfo.getName());
    }

    @Override
    public void updateTag(TagInfo tagInfo) {
        Tag tag = new Tag(tagInfo);
        tagRepository.update(tag);
    }

    /**
     * 更新标签名称：
     * 		1. 更新标签名称
     * 		2. 更新所有使用到该标签的"列表文章"的标签名称
     * 		3. 更新所有使用到该标签的文章的标签项的值
     */
    @Override
    public void updateTagName(String channelId, String originalTagName, String newTagName) {
        tagRepository.updateTagName(channelId, originalTagName, newTagName);
        final String channelIdFinal = channelId;
        final String originalTagNameFinal = originalTagName;
        final String newTagNameFinal = newTagName;
        ThreadUtil.getThreadPool().execute(new Runnable() {
			@Override
			public void run() {
				article4TagListRepository.updateTagName(channelIdFinal, originalTagNameFinal, newTagNameFinal);		
				articleRepository.updateTagName(channelIdFinal, originalTagNameFinal, newTagNameFinal);
			}
		});
    }

    @Override
    public void deleteTag(TagInfo tagInfo) {
        Tag tag = new Tag(tagInfo);
        tagRepository.delete(tag);
    }

    /**
     * 1. 删除标签数据
     * 2. 删除对应的"文章列表"数据
     * 3. 删除对应的文章的"标签输入框"的数据
     * 4. 引用到该标签的模板都会重新生成
     * 5. 把预览的HTML页面清空
     * 注意：壮秋把1,2,3业务做到tagRepository.delete方法,此处需要优化
     */
    @Override
    public void removeTagAllMsg(TagInfo tagInfo) {
        
        ChannelInfo channelInfo = channelService.getById(tagInfo.getChannelId());
        Tag tag = tagRepository.getByChannelIdAndName(tagInfo.getChannelId(), tagInfo.getName());
        if(tag==null) 
            return;
        String absoluteTagPath =  PathUtil.getAbsoluteTagPath(channelInfo.getArticleFilePath(), tag.getId(), 0);
        
        ExecutorService threadPool = ThreadUtil.getThreadPool();
        // 生成静态页面，异步实现【模板解析模块实现】
        final Tag finalTag =  new Tag(tagInfo);
        tagRepository.delete(finalTag);
        final String absoluteTagPathFinal = absoluteTagPath ; 
        threadPool.execute(new Runnable() {
			@Override
			public void run() {
	            if (FileUtil.isFileExists(absoluteTagPathFinal)) {
		            try {
		                FileUtil.write(absoluteTagPathFinal, "");
		                logger.info("成功文件:" + absoluteTagPathFinal);
		            } catch (IOException e) {
		                logger.error("清空文件" + absoluteTagPathFinal + "失败，原因：" + e.getMessage());
		            }
	            }
			}
		});
        
        // 引用到该标签的模板都会重新生成
        threadPool.execute(new Runnable() {
            public void run() {
                TemplateSearchCriteria searchCriteria = new TemplateSearchCriteria();
                searchCriteria.addRelateTags(finalTag.getName());
                List<TemplateInfo> templateInfoList = templateService.listSearch(searchCriteria);
                logger.info("重新生成引用到标签[name=" + finalTag.getName() + "]的模板，引用到该标签的模板数量是[" + templateInfoList.size() + "]个");
                for (TemplateInfo templateInfo : templateInfoList) {
                    try {
                        parserRemoteService.parseTemplateAndGenerateFile(templateInfo.getChannelInfo(), templateInfo);
                    } catch (BaseCheckedException e) {
                        logger.error("解析模板[channelId=" + finalTag.getChannel().getId() + ", templateId=" + templateInfo.getId() + "]出错，原因是：" + e.getMessage());
                    }

                }

            }
        });
    }

    @Override
    public void pasteTag(String channelId, String parentName, String originalChannelId, String originalTagName) {

        Tag originalTag = tagRepository.getByChannelIdAndName(originalChannelId, originalTagName);
        Tag destParentTag = tagRepository.getByChannelIdAndName(channelId, parentName);

        // 粘贴后成为一级标签，则无destTag
        if (destParentTag == null) {
            Tag targetTag = new Tag();
            targetTag.setChannel(new Channel(channelService.getById(channelId)));
            targetTag.setName("");
            targetTag.setTree("");
            tagRepository.moveTag(originalTag, targetTag);
        } else {
            tagRepository.moveTag(originalTag, destParentTag);
        }
        this.asynParseTagAndGenerateFile(channelId, originalTagName);
    }

    @Override
    public void addAlias(String channelId, String tagName, String alias) {
        tagRepository.updateTemplateName(channelId, tagName, alias);
    }

    @Override
    public void exchangeTagImage(String channelId, String tagName, boolean isTagImage) {
        Tag tag = tagRepository.getByChannelIdAndName(channelId, tagName);
        if (isTagImage) {
            tag.setRelatedTemplateCategory(TemplateCategory.TAG_VIEW.getDisplay());
        } else {
            tag.setRelatedTemplateCategory(TemplateCategory.TAG.getDisplay());
        }
        tagRepository.update(tag);
        this.asynParseTagAndGenerateFile(channelId, tagName);
    }

    @Override
    public List<TagInfo> getDescendantIncludeSelf(String channelId, String parent) {
        return tagRepository.getDescendantIncludeSelf(channelId, parent);
    }

    @Override
    public boolean isExist(String channelId, String tagName) {
        return null != tagRepository.getByChannelIdAndName(channelId, tagName);
    }
    
    /**
     * 异步刷新并且生成tag页面
     */
    private void asynParseTagAndGenerateFile(String channelId, String tagName){
        final ChannelInfo channelInfo =channelService.getById(channelId);
        final TagInfo tagInfo = this.getByChannelIdAndName(channelId, tagName);
        final TemplateParserRemoteService finalParserRemoteService = parserRemoteService;
        ThreadUtil.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    finalParserRemoteService.parseTagAndGenerateFile(channelInfo, tagInfo);
                } catch (BaseCheckedException e) {
                    logger.error("标签[channelId="+channelInfo.getId()+", tagName="+tagInfo.getName()+"] 解析出错，错误原因："+e.getMessage());
                }
            }
        });
    }

}
